<template>
  <div>
    <el-input class="wifont" v-model="streamStrInfo.value" :rows="4" :size="streamStrInfo.size"
              :placeholder="`请输入${streamStrInfo.placeholder}`" @blur="streamStrChanged">
      <el-button v-if="validate" slot="append" @click="clickCommandValidate">模板校验</el-button>
    </el-input>
    <div v-if="streamTags.length > 0">
      <el-tag v-for="(tag, idx) in streamTags" :key="idx" size="medium" class="mar-rgt-5 wifont"
              :class="getTagClass(tag.type)" :type="getTagColor(tag.type)" @click="clickCommandTag(tag)">
        <el-tooltip
          v-if="tag.codeStyle == 'hexadecimal' && (tag.type == 'head' || tag.type == 'separate' || tag.type == 'terminal')"
          :content="`${tag.value.length / 2}字节`" :visible-arrow="false" placement="top" :open-delay="300">
          <span v-if="!judgeHtmlTag(tag.value)" v-html="getTagSplitText(tag)"></span>
          <span v-else>{{getTagText(tag.value || tag.key)}}</span>
        </el-tooltip>
        <span v-else>
          <span v-if="!judgeHtmlTag(tag.value)" v-html="getTagSplitText(tag)"></span>
          <span v-else>{{getTagText(tag.value || tag.key)}}</span>
        </span>
      </el-tag>
    </div>

    <el-dialog title="码流模板校验" :visible.sync="showCommValDialog" width="600px" append-to-body center
               :close-on-click-modal="false" @close="clearInit">
      <el-form v-loading="commValFormLoading" :ref="commValFormRef" :model="commValForm" :rules="commValFormRules"
               size="small" label-width="130px">
        <el-form-item label="命令名称">
          <el-select v-model="genCommInfo._id" class="width-100" :disabled="true">
            <el-option :label="`${genComm.methodAlias} ${genComm.methodName}`" :value="genComm._id" :key="idx"
                       v-for="(genComm, idx) in genCommData"></el-option>
          </el-select>
        </el-form-item>
        <el-form-item label="校验类型">
          <el-radio-group v-model="validateType" :readonly="true">
            <el-radio :label="type.value" :key="idx" v-for="(type, idx) in commonConfig.analyzeFuncType"
                      :disabled="true">
              {{type.label}}
            </el-radio>
          </el-radio-group>
        </el-form-item>
        <el-form-item label="码流模板">
          <el-input v-model="streamStrInfo.value" :placeholder="`请输入${streamStrInfo.placeholder}`" :readonly="true"
                    class="wifont"></el-input>
        </el-form-item>

        <div v-if="validateType === 'encode'">
          <el-collapse class="mar-top mar-btm" v-if="commValFormStructure.length > 0">
            <el-collapse-item name="http-setting">
              <template slot="title">
                <div class="el-form-item__label font-color-warning font-weight-bold"><span>参数设置</span></div>
              </template>
              <el-form-item :label="item.label" v-for="(item, idx) in commValFormStructure" :key="idx"
                            class="mar-btm-10">
                <el-select v-if="item.type === 'select'" v-model="commValForm[item.prop]" clearable filterable
                           class="width-100">
                  <el-option :label="opt.key" :value="opt.key" :key="idx" v-for="(opt, idx) in item.options">
                  </el-option>
                </el-select>
                <el-input v-if="item.type === 'input'" v-model="commValForm[item.prop]"></el-input>
                <el-input-number v-if="item.type === 'input-number'" v-model="commValForm[item.prop]" :min="item.min"
                                 :max="item.max" class="width-100"></el-input-number>
              </el-form-item>
            </el-collapse-item>
          </el-collapse>
          <!-- <div v-if="commValFormStructure.length > 0" class="param-container">
            <span class="dtitle">参数设置</span>
            <el-form-item :label="item.label" v-for="(item, idx) in commValFormStructure" :key="idx" class="mar-btm-10">
              <el-select v-if="item.type === 'select'" v-model="commValForm[item.prop]" clearable filterable
                class="width-100">
                <el-option :label="opt.key" :value="opt.key" :key="idx" v-for="(opt, idx) in item.options"></el-option>
              </el-select>
              <el-input v-if="item.type === 'input'" v-model="commValForm[item.prop]"></el-input>
              <el-input-number v-if="item.type === 'input-number'" v-model="commValForm[item.prop]" :min="item.min"
                :max="item.max" class="width-100"></el-input-number>
            </el-form-item>
          </div> -->
          <el-form-item label="参考码流" prop="refStream">
            <el-input v-model="commValForm.refStream"></el-input>
          </el-form-item>
          <el-form-item label="校验码流(Hex)">
            <el-input v-model="commValForm.valHexStream"></el-input>
          </el-form-item>
          <el-form-item label="校验码流(Ascii)">
            <el-input v-model="commValForm.valAsciiStream"></el-input>
          </el-form-item>
        </div>
        <div v-if="validateType === 'decode'">
          <el-form-item label="码流类型">
            <el-radio-group v-model="encodeType">
              <el-radio label="hex">HEX</el-radio>
              <el-radio label="ascii">ASCII</el-radio>
            </el-radio-group>
          </el-form-item>
          <el-form-item label="码流值" prop="streamValue">
            <el-input v-model="commValForm.streamValue" placeholder="请输入码流值">
              <el-button slot="append" @click="clickTrimBtn">trim</el-button>
            </el-input>
          </el-form-item>
          <el-form-item label="解析结果" v-if="!decodeError">
            <el-input v-model="valResult" type="textarea" :rows="5"></el-input>
          </el-form-item>
          <div v-if="decodeError">
            <el-form-item label="报错码流片段">
              <el-input v-model="sliceText" type="textarea"></el-input>
            </el-form-item>
            <el-form-item label="报错模版片段">
              <el-input v-model="tplTag" type="textarea"></el-input>
            </el-form-item>
          </div>
        </div>
        <div class="text-align-right">
          <el-form-item>
            <el-button size="medium" @click="commValFormCanceled">取消</el-button>
            <el-button size="medium" type="primary" @click="commValFormSubmitted">提交</el-button>
          </el-form-item>
        </div>
      </el-form>
    </el-dialog>
  </div>
</template>

<script>
  import {dealWithModelProtocol, deepCopyWithJson, judgeSpecialTag} from "@/utils";
  import {commonConfig} from "@/config/common";
  import {msgCode} from "@/config/string";

  export default {
    name: "CommandStreamTag",
    props: {
      streamStrInfo: {
        default: () => {
          return {
            identify: '', // 页面有多个组件时的唯一标志
            value: '',
            size: '',
            placeholder: ''
          }
        }
      },
      streamTags: {
        default: () => {
          return []
        }
      },

      // 模流模板校验相关
      validate: {
        default: () => {
          return false
        }
      },
      validateType: {
        default: () => {
          return ''
        }
      },
      genCommInfo: {
        default: () => {
          return {}
        }
      },
      decodeFunc: {
        default: () => {
          return ''
        }
      },
      encodeFunc: {
        default: () => {
          return ''
        }
      },

    },
    data() {
      return {
        commonConfig: commonConfig,
        showCommValDialog: false,
        commValFormLoading: false,
        commValFormStructure: [],
        commValForm: {
          refStream: '', valHexStream: '',
          valAsciiStream: '', streamValue: ''
        },
        commValFormRules: {
          refStream: [
            {required: true, message: '请输入参考码流', trigger: ['blur', 'change']}
          ],
          streamValue: [
            {required: true, message: '请输入码流值', trigger: ['blur', 'change']}
          ],
        },
        commValFormRef: '',
        commValParams: {},
        commValParamSchema: {},
        genCommData: [],
        // encode
        // decode
        encodeType: 'hex',
        valResult: '',
        streamStrInfos: {},
        encodeFuncT: '',
        decodeFuncT: '',
        sliceText: '',
        tplTag: '',
        decodeError: false,
        streamStrInfoVal: '',//新码流
      }
    },
    watch: {
      'streamStrInfo.value': {
        handler() {
          this.analyzeCommStream();
        },
        immediate: true,
        deep: true
      },
    },
    created() {
      this.getGenCommData()
    },

    methods: {
      clearInit() {
        this.sliceText = ""
        this.tplTag = ""
        this.valResult = ""
        this.decodeError = false
        this.$refs[this.commValFormRef].resetFields()

      },
      getCodeFunc() {
        //解析编码解码对应的函数
        API.analyzeFunc.analyzeFuncList({pageNo: 1, pageSize: 1000}).then(result => {
          const {data = []} = result;
          if (this.decodeFunc) {
            var decode = data.filter(item => {
              return item._id == this.decodeFunc
            })
            this.decodeFuncT = decode ? decode[0].function : ''
          }
          if (this.encodeFunc) {
            var encode = data.filter(item => {
              return item._id == this.encodeFunc
            })
            this.encodeFuncT = encode ? encode[0].function : ''
          }
        }).catch(err => {
          console.log('err', err)
        });
      },
      streamStrChanged() {
        this.analyzeCommStream()
      },
      analyzeCommStream() {
        const srcTags = deepCopyWithJson(this.streamTags);
        // console.log('srcTags',srcTags)
        this.streamTags.length = 0;
        const destTags = dealWithModelProtocol(this.streamStrInfo.value);
        //   console.log('destTags',srcTags)
        if (!destTags || !destTags.length) return;
        for (var i = 0; i < destTags.length; i++) {
          if (destTags[i] == undefined) {
            // this.$notify({
            //   message: '请输入正确的码流模版',
            //   type: 'error',
            //   duration: 3000,
            // });
            return

          } else {
            //如果是特殊标签就要设置commadMap
            // console.log("是否是特殊属性",judgeSpecialTag(destTags[i]))
            if (judgeSpecialTag(destTags[i])) {
              const tag = srcTags.find(t => {
                return t.key === destTags[i].key
              }) || {};
              // console.log(14,srcTags)
              //  console.log(15, tag)
              // console.log(16, destTags[i].commandMap)
              destTags[i].commandMap = tag.commandMap
            }
            this.streamTags.push(destTags[i])
          }
        }

      },
      getTagClass(type) {
        switch (type) {
          case commonConfig.codeTagType.variable:
          case commonConfig.codeTagType.nLoop:
          case commonConfig.codeTagType.systemFunc:
            return 'text-underline cursor-pointer';
          case commonConfig.codeTagType.length:
          case commonConfig.codeTagType.seqNum:
          case commonConfig.codeTagType.proxy:
          case commonConfig.codeTagType.head:
          case commonConfig.codeTagType.separate:
          case commonConfig.codeTagType.terminal:
          default:
            return ''
        }
      },
      getTagColor(type) {
        switch (type) {
          case commonConfig.codeTagType.variable:
            return 'default';
          case commonConfig.codeTagType.nLoop:
            return 'success';
          case commonConfig.codeTagType.address:
            return 'warning';
          case commonConfig.codeTagType.systemFunc:
            return 'danger';
          case commonConfig.codeTagType.length:
          case commonConfig.codeTagType.seqNum:
          case commonConfig.codeTagType.proxy:
          case commonConfig.codeTagType.head:
          case commonConfig.codeTagType.separate:
          case commonConfig.codeTagType.terminal:
          default:
            return 'info'
        }
      },
      judgeHtmlTag(value = '') {
        const strValue = String(value);
        return (strValue.includes('<') || strValue.includes('>'))
      },
      getContent(tag) {
        const strValue = String(tag.value);
        if (tag.type == 'head' || tag.type == 'separate' || tag.type == 'terminal') {
          return strValue.length / 2 + '字节'
        } else {
          return ''
        }
      },
      getTagSplitText(tag) {
        const strValue = String(tag.value) || String(tag.key);
        if (strValue.trim().length === 0 || strValue === 'undefined') {
          // 增加占位透明字体 placeholder
          return '<span style="color: rgba(0, 0, 0, 0)">ph</span>'
          // else if (tag.type == 'head' || tag.type == 'separate' || tag.type == 'terminal')
          // else if (tag.codeStyle == "hexadecimal" && (tag.type == 'head' || tag.type == 'separate' || tag.type == 'terminal'))
        } else if (tag.codeStyle == "hexadecimal" && (tag.type == 'head' || tag.type == 'separate' || tag.type == 'terminal')) {
          var result = "";
          for (let i = 0; i < strValue.length; i++) {
            result += strValue[i];
            if (i % 2 === 1) result += ' ';
          }
          return result
        } else {
          return strValue
        }
      },

      getTagText(value = ' ') {
        const strValue = String(value);
        if (strValue.trim().length === 0) {
          // 增加占位透明字体 placeholder
          return '<span style="color: rgba(0, 0, 0, 0)">ph</span>'
        } else {
          return strValue
        }
      },
      clickCommandTag(tag = {}) {
        if (!judgeSpecialTag(tag)) return;
        this.$emit('clickCommandTag', this.streamStrInfo.identify, tag);
      },
      getGenCommData() {
        API.genCommand.genCommAll().then(result => {
          const {data = []} = result;
          this.genCommData = data;
        }).catch(err => {
          console.log('err', err)
        });
      },
      clickTrimBtn() {
        this.commValForm.streamValue = this.commValForm.streamValue.replace(/\s/g, "");
      },
      clickCommandValidate() {
        console.log('##### streamTags #####', this.streamTags);
        console.log('##### genCommInfo #####', this.genCommInfo);
        const commValForm = {};
        this.commValForm = {};
        this.commValParams = {};
        this.commValParamSchema = {};
        this.commValFormStructure = [];
        const {statusParams = [], controlParams = []} = this.genCommInfo;
        var that = this

        function getParamFromGenComm(value) {
          return (that.validateType === commonConfig.analyzeFuncType[0].value
            ? controlParams : statusParams).find(s => {
            return s.paramKey === value
          }) || {};
        }

        this.streamTags.forEach(s => {
          // 地址标签需要手动填入参数
          if (s.type === commonConfig.codeTagType.address) {
            this.commValFormStructure.push({
              type: 'input',
              prop: 'address',
              label: '地址',
            });
            commValForm['address'] = '';
          }
          if (s.commandMap) {
            const {
              paramName, dataType, dataLen, byteOrder,
              scale, unit, enumList, field, mapWay
            } = s.commandMap;
            const paramInfo = getParamFromGenComm(paramName);
            this.commValParams[s.key] = paramName;
            this.commValParamSchema[paramName] = {
              propertyName: paramName,
              dataType, dataLen,
              byteOrder, scale, unit, storeKey: paramInfo.storeKey
            };
            switch (mapWay) {
              case commonConfig.commandMapWay[1].value:
                this.commValFormStructure.push({
                  type: enumList.length > 0 ? 'select' : 'input',
                  prop: paramName,
                  label: paramInfo.paramAlias || paramName,
                  options: enumList
                });
                commValForm[paramName] = '';
                enumList.length > 0 && (this.commValParamSchema[paramName]['enumList'] = enumList);
                break;
              case commonConfig.commandMapWay[2].value:
                const {preMin = 0, preMax = 100} = field;
                this.commValFormStructure.push({
                  type: 'input-number',
                  prop: paramName,
                  label: paramInfo.paramAlias || paramName,
                  min: preMin,
                  max: preMax,
                });
                commValForm[paramName] = 0;
                this.commValParamSchema[paramName]['field'] = JSON.stringify(field);
                break;
              default:
                break;
            }
          }
        });
        this.$set(this, 'commValForm', commValForm);
        this.getCodeFunc()
        this.showCommValDialog = true;
      },
      commValFormCanceled() {
        this.showCommValDialog = false;
      },
      commValFormSubmitted() {
        this.$refs[this.commValFormRef].validate((valid) => {
          if (!valid) return;
          let params = {};
          switch (this.validateType) {
            case commonConfig.analyzeFuncType[0].value:
              params = {
                method: this.validateType,
                data: {
                  params: this.commValForm,
                  paramKeyMap: this.commValParams,
                  paramSchemas: this.commValParamSchema,
                  stream: this.streamStrInfo.value,
                  decodeFunc: this.decodeFuncT
                },
              };
              break;
            case commonConfig.analyzeFuncType[1].value:
              params = {
                method: this.validateType,
                data: {
                  paramKeyMap: this.commValParams,
                  paramSchemas: this.commValParamSchema,
                  // codeArray: [
                  //   {
                  //     stream: this.streamStrInfo.value
                  //   },
                  // ],
                  stream: this.streamStrInfo.value,
                  payload: this.commValForm.streamValue,
                  type: this.encodeType,
                  encodeFunc: this.encodeFuncT
                },
              };
              break;
            default:
              break;
          }
          console.log('##### params #####', params);
          this.commValFormLoading = true;
          API.command.commandCheck(params).then(result => {
            this.commValFormLoading = false;
            switch (this.validateType) {
              case commonConfig.analyzeFuncType[0].value:
                const {hex = '', ascii = ''} = result.data || {};
                this.commValForm.valHexStream = hex;
                this.commValForm.valAsciiStream = ascii;
                var regex = new RegExp('^' + this.commValForm.refStream + '$', 'i');
                if (regex.test(hex) || regex.test(ascii)) {
                  this.$notify({
                    message: '码流校验成功',
                    type: 'success',
                    duration: 3000,
                  });
                } else {
                  this.$notify({
                    message: '码流校验失败',
                    type: 'warning',
                    duration: 3000,
                  });
                }
                break;
              case commonConfig.analyzeFuncType[1].value:
                const {error = {}} = result || {};
                if (result.error) {
                  this.$notify({
                    message: error.errMsg,
                    type: 'warning',
                    duration: 3000,
                  });
                  this.decodeError = true
                  this.sliceText = error.sliceText || '-'
                  this.tplTag = error.tplTag || '-'
                } else {
                  this.decodeError = false
                  this.valResult = JSON.stringify(result.data, null, 4) || ''
                }


                break;
              default:
                break;
            }
          }).catch(err => {
            this.commValFormLoading = false;
            console.log('err: ', err);
          });
        })

        // Meteor.call('command_validate', params, (err, result) => {
        //   this.commValFormLoading = false;
        //   if (err) {
        //     console.log('##### err #####', err);
        //     messageHandler({ code: msgCode.SYSTEM });
        //   } else {
        //     console.log('##### result #####', result);
        //     this.$notify({
        //       message: '码流校验成功',
        //       type: 'success',
        //       duration: 3000,
        //     });
        //     switch (this.validateType) {
        //       case commonConfig.analyzeFuncType[0].value:
        //         const { hex = '', ascii = '' } = result.data || {};
        //         this.valHexStream = hex;
        //         this.valAsciiStream = ascii;
        //         break;
        //       case commonConfig.analyzeFuncType[1].value:
        //         this.valResult = JSON.stringify(result.data);
        //         break;
        //       default:
        //         break;
        //     }
        //   }
        // })
      },
    },
  }
</script>

<style lang="less" scoped>
  .wifont {
    font-family: Menlo, Monaco, 'Courier New', monospace !important;

    /deep/ .el-input__inner {
      font-family: Menlo, Monaco, 'Courier New', monospace !important;
    }
  }


  .param-container {
    border-radius: 8px;
    background: #fafafa;
    padding: 15px 15px 1px 0;
    margin-bottom: 15px;
  }
</style>
